package com.joysuch.wwyt.workflow.service.impl;

import cn.zlg.common.util.CollectionUtils;
import com.joysuch.wwyt.core.bean.AuthorityBean;
import com.joysuch.wwyt.core.common.ajax.ResultBean;
import com.joysuch.wwyt.core.constant.Constants;
import com.joysuch.wwyt.core.entity.BaseMenuFunction;
import com.joysuch.wwyt.core.enums.MenuTypes;
import com.joysuch.wwyt.core.enums.Status;
import com.joysuch.wwyt.core.exception.ApiBusinessException;
import com.joysuch.wwyt.core.repository.BaseMenuFunctionDao;
import com.joysuch.wwyt.util.SpringBeanUtils;
import com.joysuch.wwyt.workflow.WorkFlowConstants;
import com.joysuch.wwyt.workflow.bean.WorkFlowMenuBean;
import com.joysuch.wwyt.workflow.bean.WorkFlowMenuSystemBean;
import com.joysuch.wwyt.workflow.entity.WorkFlowMenu;
import com.joysuch.wwyt.workflow.entity.WorkFlowProcess;
import com.joysuch.wwyt.workflow.repository.WorkFlowMenuDao;
import com.joysuch.wwyt.workflow.repository.WorkFlowProcessDao;
import com.joysuch.wwyt.workflow.service.WorkFlowMenuService;
import com.joysuch.wwyt.workflow.service.WorkFlowProcessService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.transaction.Transactional;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 业务流程菜单配置管理接口
 */

@Slf4j
@Service
@Transactional
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class WorkFlowMenuServiceImpl implements WorkFlowMenuService {


    @Autowired
    private WorkFlowMenuDao workFlowMenuDao;

    @Autowired
    private WorkFlowProcessService workFlowProcessService;

    @Autowired
    private BaseMenuFunctionDao baseMenuFunctionDao;

    @Autowired
    private WorkFlowProcessDao workFlowProcessDao;


    @Override
    public String getTaskNameList(Long processId) {
        WorkFlowProcess process = workFlowProcessService.findById(processId).get();
        return process.getTaskNameList();
    }

    @Override
    public List<WorkFlowMenu> getMenuList(Long processId) {
        List<WorkFlowMenu> menuList = workFlowMenuDao.findAllByWorkFlowIdOrderByShowOrder(processId);
        menuList.forEach(each -> {
            if (each.getParentMenuId() != null) {
                Optional<BaseMenuFunction> optional = baseMenuFunctionDao.findById(each.getParentMenuId());
                if (optional.isPresent()) {
                    BaseMenuFunction baseMenu = optional.get();
                    each.setParentMenu(baseMenu.getName());
                }
            }
        });
        return menuList;
    }

    @Override
    @Transactional(rollbackOn = Exception.class)
    public void saveProcessMenu(WorkFlowMenuBean bean) throws ApiBusinessException {
        final Long workFlowId = bean.getWorkFlowId();
        List<WorkFlowMenu> workFlowMenus = workFlowMenuDao.findAllByWorkFlowId(workFlowId);
        if (bean.getId() != null && workFlowMenus.stream().anyMatch(each -> !each.getId().equals(bean.getId()) && each.getIsAssignUser().equals(bean.getIsAssignUser()))) {
            throw new ApiBusinessException(Status.TODO_OR_ALL_MENU_NOT_DUPLICATE_ERROR);
        }
        if (bean.getId() == null && workFlowMenus.stream().anyMatch(each -> each.getIsAssignUser().equals(bean.getIsAssignUser()))) {
            throw new ApiBusinessException(Status.TODO_OR_ALL_MENU_NOT_DUPLICATE_ERROR);
        }
        WorkFlowMenu entity = getWorkFlowMenu(bean);
        final String oldMenuName = entity.getMenuName();
        SpringBeanUtils.copyProperties(bean, entity, true);
        //待办
        if (entity.getIsAssignUser() == 0) {
            BaseMenuFunction function = null;
            BaseMenuFunction parentMenuFunction = getParentBaseMenuFunction(bean.getParentMenuId());
            List<BaseMenuFunction> childMenuList = baseMenuFunctionDao.findByParent(parentMenuFunction);
            Long baseMenuId = entity.getBaseMenuId();
            if (baseMenuId != null) {
                Map<Long, String> menuMap = childMenuList.stream().collect(Collectors.toMap(BaseMenuFunction::getId, BaseMenuFunction::getName));
                menuMap.remove(baseMenuId);
                if (menuMap.containsValue(bean.getMenuName())) {
                    throw new ApiBusinessException(Status.SUBMENU_DUPLICATE_UNDER_THE_PARENT_MENU);
                }
                function = updateBaseMenuFunction(entity, parentMenuFunction);
            } else {
                //兼容老数据
                List<BaseMenuFunction> filterList = null;
                if (StringUtils.isNotBlank(oldMenuName)) {
                    filterList = childMenuList.stream().filter(each -> oldMenuName.equals(each.getName())).collect(Collectors.toList());
                }
                if (CollectionUtils.isEmpty(filterList)) {
                    function = insertBaseMenuFunction(workFlowId, entity, parentMenuFunction);
                } else {
                    //存在对应的数据即更新
                    if (filterList.size() == 1) {
                        baseMenuId = filterList.get(0).getId();
                        if (baseMenuId != null) {
                            entity.setBaseMenuId(baseMenuId);
                        }
                        function = updateBaseMenuFunction(entity, parentMenuFunction);
                    } else if (filterList.size() > 1) {
                        //兼容旧数据
                        produceBaseMenu(workFlowId);
                    }
                }
            }
            if (function != null) {
                entity.setBaseMenuId(function.getId());
                //待办菜单默认添加全部查询按钮
                addDefaultButton(function, workFlowId);
            }
            entity.setParentMenu(parentMenuFunction.getName());
        }
        workFlowMenuDao.save(entity);
    }

    private WorkFlowMenu getWorkFlowMenu(WorkFlowMenuBean bean) {
        WorkFlowMenu entity = new WorkFlowMenu();
        if (bean.getId() != null) {
            Optional<WorkFlowMenu> optionalWorkFlowMenu = workFlowMenuDao.findById(bean.getId());
            if (optionalWorkFlowMenu.isPresent()) {
                entity = optionalWorkFlowMenu.get();
            }
        }
        return entity;
    }

    private BaseMenuFunction getParentBaseMenuFunction(Long parentMenuId) throws ApiBusinessException {
        Optional<BaseMenuFunction> optionalMenuFunction = baseMenuFunctionDao.findById(parentMenuId);
        if (!optionalMenuFunction.isPresent()) {
            throw new ApiBusinessException(Status.PARENT_MENU_NOT_EXIST);
        }
        return optionalMenuFunction.get();
    }

    private BaseMenuFunction updateBaseMenuFunction(final WorkFlowMenu entity, BaseMenuFunction parentMenuFunction) {
        Optional<BaseMenuFunction> optionalFunction = baseMenuFunctionDao.findById(entity.getBaseMenuId());
        BaseMenuFunction function;
        if (optionalFunction.isPresent()) {
            function = optionalFunction.get();
        } else {
            function = new BaseMenuFunction();
            function.setType(MenuTypes.MENU.getCode());
            function.setWorkFlowId(entity.getWorkFlowId());
        }
        if (Constants.APP_MENU.equals(entity.getAppFlag())) {
            function.setAppMenuUrl(APP_MENU_URL);
        }
        if(StringUtils.isBlank(function.getAppName())){
            function.setAppName(entity.getMenuName());
        }
        function.setName(entity.getMenuName());
        function.setMenuOrder(entity.getShowOrder());
        function.setAppFlag(entity.getAppFlag());
        function.setParent(parentMenuFunction);
        return baseMenuFunctionDao.save(function);
    }

    private BaseMenuFunction insertBaseMenuFunction(final Long workFlowId, WorkFlowMenu entity, BaseMenuFunction parentMenuFunction) {
        BaseMenuFunction function = new BaseMenuFunction();
        function.setName(entity.getMenuName());
        function.setParent(parentMenuFunction);
        function.setDepth(parentMenuFunction.getDepth() + 1);
        function.setWorkFlowId(workFlowId);
        function.setType(MenuTypes.MENU.getCode());
        function.setUrl(MENU_URL);
        function.setMenuOrder(entity.getShowOrder());
        function.setAppFlag(entity.getAppFlag());
        if (Constants.APP_MENU.equals(entity.getAppFlag())) {
            function.setAppMenuUrl(APP_MENU_URL);
        }
        function.setAppName(entity.getAppName());
        function.setShowState(1);
        return baseMenuFunctionDao.save(function);
    }

    private void addDefaultButton(BaseMenuFunction parent, Long workFlowId) {
        List<BaseMenuFunction> menuFunctions = baseMenuFunctionDao.findByParentId(parent.getId());
        if (menuFunctions.stream().noneMatch(each -> Constants.MENU_TYPE_ALL_SELECT_BUTTON.equals(each.getName()))) {
            BaseMenuFunction defaultButton = new BaseMenuFunction();
            defaultButton.setParent(parent);
            defaultButton.setDepth(parent.getDepth() != null ? parent.getDepth() + 1 : 1);
            defaultButton.setName(Constants.MENU_TYPE_ALL_SELECT_BUTTON);
            defaultButton.setPerm(Constants.MENU_TYPE_ALL_SELECT_PERM);
            defaultButton.setMenuOrder(0);
            defaultButton.setType(MenuTypes.BUTTON.getCode());
            defaultButton.setWorkFlowId(workFlowId);
            defaultButton.setAppFlag(parent.getAppFlag());
            defaultButton.setShowState(1);
            baseMenuFunctionDao.save(defaultButton);
        }
    }

    @Override
    public WorkFlowMenu getById(Long menuId) {
        return workFlowMenuDao.findById(menuId).get();
    }

    @Override
    public void deleteMenu(Long menuId) {
        Optional<WorkFlowMenu> optionalMenu = workFlowMenuDao.findById(menuId);
        if (optionalMenu.isPresent()) {
            WorkFlowMenu menu = optionalMenu.get();
            if (menu.getBaseMenuId() != null) {
                baseMenuFunctionDao.deleteById(menu.getBaseMenuId());
            } else {
                //兼容旧数据
                List<BaseMenuFunction> workFlowMenuList = baseMenuFunctionDao.findByWorkFlowIdAndType(menu.getWorkFlowId(), MenuTypes.MENU.getCode());
                List<BaseMenuFunction> filterList = workFlowMenuList.stream().filter(each -> menu.getMenuName().equals(each.getName())).collect(Collectors.toList());
                if (filterList.size() == 1) {
                    baseMenuFunctionDao.deleteById(filterList.get(0).getId());
                }
            }
            workFlowMenuDao.deleteById(menuId);
        }
    }


    @Override
    public List<WorkFlowMenuSystemBean> getSystemList() {
        List<BaseMenuFunction> menuList = baseMenuFunctionDao.findByDepth(1);
        List<WorkFlowMenuSystemBean> list = new ArrayList<>();
        if (menuList != null) {
            for (BaseMenuFunction menu : menuList) {
                WorkFlowMenuSystemBean system = new WorkFlowMenuSystemBean();
                system.setSystemId(menu.getId());
                system.setSystemName(menu.getName());
                list.add(system);
            }
        }
        return list;
    }


    @Override
    public Map<Long, List<AuthorityBean>> findWorkFlowMenuList() {
        Map<Long, List<AuthorityBean>> authMap = new HashMap<>();

        List<WorkFlowProcess> processList = workFlowProcessDao.findAll();
        if (processList == null) {
            return null;
        }
        for (WorkFlowProcess process : processList) {
            //业务流程名称作为父菜单项
            AuthorityBean auth = new AuthorityBean();
            auth.setId(process.getId());
            auth.setName(process.getBizName());
            auth.setLabel(process.getBizName());

            auth.setWorkFlowId(process.getId());
            auth.setType(WorkFlowConstants.WORK_FLOW_SYSTEM_MENU_TYPE);
            auth.setIcon("icon_qlc_sggl");  //TODO set Icon
            List<WorkFlowMenu> menuList = workFlowMenuDao.findAllByWorkFlowIdOrderByShowOrder(process.getId());
            if (menuList != null) {
                //添加子菜单
                for (WorkFlowMenu menu : menuList) {
                    AuthorityBean m = new AuthorityBean();
                    m.setId(menu.getId());

                    m.setWorkFlowId(process.getId());
                    m.setLabel(menu.getMenuName());
                    m.setName(WorkFlowConstants.WORK_FLOW_SYSTEM_MENU_NAME);
                    m.setLabel(menu.getMenuName());
                    m.setIcon(menu.getMenuIcon());
                    m.setUrl(menu.getMenuUrl());
                    m.setOrder(menu.getShowOrder());
                    m.setType(WorkFlowConstants.WORK_FLOW_SYSTEM_MENU_TYPE);

                    auth.addChild(m);
                }
            }

        }
        return authMap;
    }

    private static final String MENU_URL = "/system-turn/process-page/";
    private static final String APP_MENU_URL = "/pages/engine/page_process_task_list";

    /**
     * 注意事项：
     * 1.多级菜单的业务流程在配置的时候，业务名称和业务类型名称必须不一样，一样(或者业务类型名称为null)即认为是非多级菜单
     */
    @Override
    public ResultBean produceBaseMenu(Long processId) {
        List<WorkFlowMenu> menuList = getMenuList(processId);
        /*if (CollectionUtils.isEmpty(menuList)) {
            return ResultBean.fail(Status.NOT_CONFIGURE_MENU_ERROR);
        }*/
        //同名菜单过滤
        Map<String, Long> longMap = menuList.stream().collect(Collectors.groupingBy(WorkFlowMenu::getMenuName, Collectors.counting()));
        Collection<Long> values = longMap.values();
        for (Long value : values) {
            if (value > 1) {
                return ResultBean.fail(Status.MENU_DUPLICATE_ERROR);
            }
        }

        long count = menuList.stream().filter(r -> "是".equals(r.getAppFlag())).count();
        //是否是app菜单
        String appFlag = count > 0 ? "是" : "否";

        WorkFlowProcess process = workFlowProcessDao.findById(processId).orElseThrow(() -> new IllegalArgumentException("此流程不存在"));
        String bizTypeName = process.getBizTypeName();
        BaseMenuFunction parentMenu = baseMenuFunctionDao.findFirstByTypeAndName(MenuTypes.FOLDER.getCode(), bizTypeName);
        if (parentMenu == null) {
            //生成父菜单集合
            //二级菜单
            BaseMenuFunction secondFunction = getSecondMenuFunction(processId, bizTypeName, appFlag);
            parentMenu = baseMenuFunctionDao.save(secondFunction);
        } else {
            //旧代码 作业票申请验收菜单逻辑
//            //如果二级菜单与三级菜单appFlag不一致
//            if (!appFlag.equals(parentMenu.getAppFlag())) {
//                parentMenu.setAppFlag(appFlag);
//                parentMenu.setAppName("是".equals(appFlag) ? parentMenu.getName() : null);
//                baseMenuFunctionDao.save(parentMenu);
//            }
        }

        List<BaseMenuFunction> childList = baseMenuFunctionDao.findByWorkFlowIdAndExcludeType(processId, MenuTypes.FOLDER.getCode());
        Map<String, BaseMenuFunction> childMap = childList.stream().collect(Collectors.toMap(BaseMenuFunction::getName, Function.identity(), (r, v) -> r));
        //删除"全部"菜单,不需要生成
        menuList.removeIf(menu -> Constants.MENU_TYPE_ALL_MENU.equals(menu.getMenuName()));
        for (WorkFlowMenu menu : menuList) {
            BaseMenuFunction temp = childMap.get(menu.getMenuName());
            BaseMenuFunction newFunction;
            if (temp == null) {
                BaseMenuFunction function = getChildMenuFunction(processId, parentMenu, menu);
                newFunction = baseMenuFunctionDao.save(function);
            } else {
                temp.setMenuOrder(menu.getShowOrder());
                temp.setAppFlag(menu.getAppFlag());
                temp.setAppName(menu.getAppName());
                newFunction = baseMenuFunctionDao.save(temp);
            }
            //待办菜单默认添加全部按钮
            if (menu.getIsAssignUser() == 0) {
                addDefaultButton(newFunction, processId);
            }
            childList.remove(temp);
        }
        //移除已被删除的菜单,全部查询父菜单删除时也删除全部查询的按钮
        Optional<BaseMenuFunction> optionalMenuParent = childList.stream().filter(each -> Constants.MENU_TYPE_ALL_SELECT_BUTTON.equals(each.getName())).map(BaseMenuFunction::getParent).findFirst();
        if (optionalMenuParent.isPresent()) {
            if (childList.stream().noneMatch(each -> each.getId().equals(optionalMenuParent.get().getId()))) {
                childList.removeIf(each -> Constants.MENU_TYPE_ALL_SELECT_BUTTON.equals(each.getName()));
            }
        }
        baseMenuFunctionDao.deleteAll(childList);
        return ResultBean.defaultSuccessResult();
    }

    private BaseMenuFunction getChildMenuFunction(Long processId, BaseMenuFunction parentMenu, WorkFlowMenu menu) {
        BaseMenuFunction function = new BaseMenuFunction();
        function.setName(menu.getMenuName());
        function.setParent(parentMenu);
        function.setDepth(parentMenu.getDepth() + 1);
        function.setWorkFlowId(processId);
        function.setType(MenuTypes.MENU.getCode());
        function.setUrl(MENU_URL);
        function.setMenuOrder(menu.getShowOrder());
        function.setAppFlag(menu.getAppFlag());
        function.setAppName(menu.getAppName());
        function.setShowState(1);
        return function;
    }

    private BaseMenuFunction getSecondMenuFunction(Long processId, String bizName, String appFlag) {
        BaseMenuFunction function = new BaseMenuFunction();
        BaseMenuFunction parent = baseMenuFunctionDao.findFirstByParentIdIsNull();
        function.setParent(parent);
        function.setDepth(parent != null && parent.getDepth() != null ? parent.getDepth() + 1 : 1);
        function.setUrl(MENU_URL);
        function.setName(bizName);
        function.setMenuOrder(50);
        function.setType(MenuTypes.FOLDER.getCode());
        function.setWorkFlowId(processId);
        function.setAppFlag(appFlag);
        function.setAppName("是".equals(appFlag) ? bizName : null);
        function.setShowState(1);
        //添加业务流程引擎菜单默认图标
        function.setIcon("system");
        return function;
    }

}
